package cn.itcast.direct;

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component;

import java.io.IOException;


@Component
public class ErrorConsumer {

    /**
     * 监听消息的方法
     */
//    @RabbitListener(bindings = @QueueBinding(
//            value = @Queue(name = "${direct.error.queue}", arguments = {
//                        @Argument(name = "x-max-length", value = "3", type = "java.lang.Long"), // 队列存储大小
//                        @Argument(name = "x-message-ttl", value = "500000000", type = "java.lang.Long"), // 消息存活时长
//                        @Argument(name = "x-dead-letter-exchange", value = "dlx.exchange"), // 死信队列交换机
//                        @Argument(name = "x-dead-letter-routing-key", value = "xxx") // 死信队列路由key
//                    }), // 队列
//            key = {"info", "error"}, // 路由键
//            exchange = @Exchange(name = "${log.direct}", type = ExchangeTypes.DIRECT))) // 交换机
//    public void handlerMesage(String msg, Channel channel, Message message){
//        try {
//            System.out.println("===============");
//            // 接收消息之后，业务处理 id
//            int i = 10 / 0;
//
//            System.out.println("error--->接受到的消息是：" + msg);
//
//            // 手动确认
//            /**
//             * long deliveryTag 消息唯一标识
//             * boolean multiple 单条或批量
//             */
//            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
//        }catch (Exception ex){
//            // 为了消息不积压，我们重新再消费一次，如果还不成功的话，就拒绝
//            // redelivered可以判断出消息是第一次消费，还是重复消费
//            boolean redelivered = message.getMessageProperties().getRedelivered();
//            System.out.println("redelivered = " + redelivered);
//            try {
//                if (redelivered) { // 多次消费
//                    /**
//                     * 拒绝确认
//                     * long deliveryTag: 消息唯一id
//                     * boolean requeue: 是否重投
//                     */
//                    channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
//                    System.out.println("=======消息拒绝确认，扔到死信列队中==========");
//
//                } else { // 第一次消费
//                    /**
//                     * 消息重投
//                     * long deliveryTag: 消息唯一id
//                     * boolean multiple: 单条或批量
//                     * boolean requeue: 是否重投
//                     */
//                    channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
//                    System.out.println("=======消息重回队列==========");
//                }
//            }catch (Exception e){
//            }
//        }
//    }


    /**
     * 消息监听方法
     * bindings: 配置队列 通过路由key绑定到 交换机
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "${direct.error.queue}", arguments = {
                    @Argument(name="x-dead-letter-exchange", value = "dlx.exchange"),
                    @Argument(name = "x-message-ttl",value = "5000",type = "java.lang.Long"),
                    @Argument(name="x-dead-letter-routing-key", value = "xxx")}), // 队列
            key = {"info","error"}, // 路由key
            exchange = @Exchange(name = "${log.direct}",
                    type = ExchangeTypes.DIRECT))) // 交换机
    public void handlerMessage(String msg, Channel channel,
                               Message message){
        try {
            System.out.println("================");
            // 制造异常
            int i = 10 / 0;
            System.out.println("error--->接受到的消息是：" + msg);
            // 手动ack确认
            // 参数1：deliveryTag:消息唯一传输ID
            // 参数2：multiple：true: 手动批量处理，false: 手动单条处理
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }catch (Exception ex){
            // 如果真得出现了异常，我们采用消息重投
            // 获取redelivered，判断是否为重投: false没有重投，true重投
            Boolean redelivered = message.getMessageProperties().getRedelivered();
            System.out.println("redelivered = " + redelivered);
            try {
                // 判断是否为重新消费
                if (redelivered) { // 重新消费
                    /**
                     * 拒绝确认，从队列中删除该消息，防止队列阻塞(消息堆积)
                     * boolean requeue: false不重新入队列(丢弃消息)
                     */
                    channel.basicReject(message.getMessageProperties()
                            .getDeliveryTag(), false);
                    System.out.println("消息已重新存入死信队列了。。。");
                } else { // 第一次消费

                    /**
                     * 消息重投，重新把消息放回队列中
                     * boolean multiple: 单条或批量
                     * boolean requeue: true重回队列
                     */
                    channel.basicNack(message.getMessageProperties()
                            .getDeliveryTag(), false, true);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

}
